package com.kh.rationaldrugreview.service;

import com.kh.rationaldrugreview.entity.*;
import com.kh.rationaldrugreview.neo4j.entity.DrugNode;
import com.kh.rationaldrugreview.neo4j.service.DrugKnowledgeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Slf4j
public class DrugReviewService {
    
    private final DrugKnowledgeService drugKnowledgeService;
    private final PrescriptionService prescriptionService;
    
    public List<ReviewResult> reviewPrescription(Long prescriptionId) {
        log.info("Starting review for prescription ID: {}", prescriptionId);
        
        Prescription prescription = prescriptionService.findById(prescriptionId);
        if (prescription == null) {
            throw new RuntimeException("Prescription not found: " + prescriptionId);
        }
        
        List<ReviewResult> reviewResults = new ArrayList<>();
        
        // 基于知识图谱和业务逻辑的审查
        reviewResults.addAll(checkDrugInteractions(prescription));
        reviewResults.addAll(checkContraindications(prescription));
        
        // 业务逻辑审查
        reviewResults.addAll(checkDuplicateDrugs(prescription));
        reviewResults.addAll(checkAgeRestrictions(prescription));
        reviewResults.addAll(checkDosageValidation(prescription));
        reviewResults.addAll(checkSpecialPopulations(prescription));
        reviewResults.addAll(checkGenderRestrictions(prescription));
        
        // 去重并更新处方审查状态
        reviewResults = deduplicateResults(reviewResults);
        updatePrescriptionReviewStatus(prescription, reviewResults);
        
        log.info("Review completed for prescription ID: {}. Found {} issues.", prescriptionId, reviewResults.size());
        return reviewResults;
    }
    
    
    private List<ReviewResult> checkDrugInteractions(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        
        if (items == null || items.size() < 2) {
            return results;
        }
        
        for (int i = 0; i < items.size(); i++) {
            for (int j = i + 1; j < items.size(); j++) {
                PrescriptionItem item1 = items.get(i);
                PrescriptionItem item2 = items.get(j);
                
                Object interaction = drugKnowledgeService.findInteractionBetweenDrugs(
                    item1.getDrugCode(), item2.getDrugCode());
                
                if (interaction != null) {
                    ReviewResult result = createReviewResult(
                        prescription.getPrescriptionId(),
                        "DRUG_INTERACTION",
                        "WARNING",
                        String.format("药物相互作用：%s 与 %s 存在相互作用", 
                            item1.getDrugName(), item2.getDrugName()),
                        "请医师评估药物相互作用的风险，考虑调整用药方案",
                        String.format("%s, %s", item1.getDrugName(), item2.getDrugName()),
                        "检测到药物间可能存在相互作用"
                    );
                    results.add(result);
                }
            }
        }
        
        return results;
    }
    
    private List<ReviewResult> checkContraindications(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        Patient patient = prescription.getPatient();
        
        if (patient == null) {
            return results;
        }
        
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        if (items == null) {
            return results;
        }
        
        for (PrescriptionItem item : items) {
            Optional<DrugNode> drugNodeOpt = drugKnowledgeService.findDrugByCode(item.getDrugCode());
            if (drugNodeOpt.isPresent()) {
                DrugNode drugNode = drugNodeOpt.get();
                // 使用知识图谱查询禁忌症
                List<DrugNode> contraindicatedDrugs = drugKnowledgeService.findDrugsContraindicatedFor(patient.getMedicalHistory());
                if (contraindicatedDrugs.stream().anyMatch(d -> d.getDrugCode().equals(item.getDrugCode()))) {
                    ReviewResult result = createReviewResult(
                        prescription.getPrescriptionId(),
                        "CONTRAINDICATION",
                        "ERROR",
                        String.format("禁忌症：患者不适宜使用 %s", item.getDrugName()),
                        "建议更换其他药物",
                        item.getDrugName(),
                        "患者存在该药物的禁忌症"
                    );
                    results.add(result);
                }
            }
        }
        
        return results;
    }
    
    private List<ReviewResult> checkDuplicateDrugs(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        
        if (items == null) {
            return results;
        }
        
        Map<String, List<PrescriptionItem>> activeIngredientMap = new HashMap<>();
        
        for (PrescriptionItem item : items) {
            Optional<DrugNode> drugNodeOpt = drugKnowledgeService.findDrugByCode(item.getDrugCode());
            if (drugNodeOpt.isPresent()) {
                DrugNode drugNode = drugNodeOpt.get();
                String ingredient = drugNode.getActiveIngredient();
                if (ingredient != null) {
                    activeIngredientMap.computeIfAbsent(ingredient, k -> new ArrayList<>()).add(item);
                }
            }
        }
        
        for (Map.Entry<String, List<PrescriptionItem>> entry : activeIngredientMap.entrySet()) {
            if (entry.getValue().size() > 1) {
                String drugNames = entry.getValue().stream()
                    .map(PrescriptionItem::getDrugName)
                    .collect(Collectors.joining(", "));
                
                ReviewResult result = createReviewResult(
                    prescription.getPrescriptionId(),
                    "DUPLICATE_DRUG",
                    "WARNING",
                    String.format("重复用药：存在相同有效成分的药物 - %s", entry.getKey()),
                    "请确认是否需要同时使用这些药物",
                    drugNames,
                    "检测到含有相同有效成分的多个药物"
                );
                results.add(result);
            }
        }
        
        return results;
    }
    
    private List<ReviewResult> checkAgeRestrictions(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        Patient patient = prescription.getPatient();
        
        if (patient == null || patient.getAge() == null) {
            return results;
        }
        
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        if (items == null) {
            return results;
        }
        
        for (PrescriptionItem item : items) {
            Optional<DrugNode> drugNodeOpt = drugKnowledgeService.findDrugByCode(item.getDrugCode());
            if (drugNodeOpt.isPresent()) {
                DrugNode drugNode = drugNodeOpt.get();
                if (checkAgeRestriction(patient.getAge(), drugNode)) {
                    ReviewResult result = createReviewResult(
                        prescription.getPrescriptionId(),
                        "AGE_RESTRICTION",
                        "WARNING",
                        String.format("年龄限制：%s 可能不适合 %d 岁患者使用", 
                            item.getDrugName(), patient.getAge()),
                        "请确认该药物对此年龄段患者的安全性",
                        item.getDrugName(),
                        "患者年龄可能不在该药物的适用范围内"
                    );
                    results.add(result);
                }
            }
        }
        
        return results;
    }
    
    private List<ReviewResult> checkDosageValidation(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        
        if (items == null) {
            return results;
        }
        
        for (PrescriptionItem item : items) {
            if (item.getDosage() == null || item.getDosage().doubleValue() <= 0) {
                ReviewResult result = createReviewResult(
                    prescription.getPrescriptionId(),
                    "DOSAGE_ERROR",
                    "ERROR",
                    String.format("剂量错误：%s 的剂量信息不正确", item.getDrugName()),
                    "请重新确认并输入正确的剂量",
                    item.getDrugName(),
                    "药物剂量信息缺失或不正确"
                );
                results.add(result);
            }
        }
        
        return results;
    }
    
    private boolean checkPatientContraindication(Patient patient, String contraindication) {
        if (contraindication == null) {
            return false;
        }
        
        String lowerContraindication = contraindication.toLowerCase();
        
        if (patient.getIsPregnant() != null && patient.getIsPregnant() && 
            (lowerContraindication.contains("妊娠") || lowerContraindication.contains("孕妇"))) {
            return true;
        }
        
        if (patient.getIsLactating() != null && patient.getIsLactating() && 
            (lowerContraindication.contains("哺乳") || lowerContraindication.contains("授乳"))) {
            return true;
        }
        
        if (patient.getAllergies() != null && 
            contraindication.contains("过敏") && 
            patient.getAllergies().toLowerCase().contains("过敏")) {
            return true;
        }
        
        return false;
    }
    
    private boolean checkAgeRestriction(Integer age, DrugNode drugNode) {
        if (drugNode.getPrecaution() == null) {
            return false;
        }
        
        String precaution = drugNode.getPrecaution().toLowerCase();
        
        if (age < 18 && (precaution.contains("儿童") || precaution.contains("小儿") || precaution.contains("未成年"))) {
            return true;
        }
        
        if (age >= 65 && (precaution.contains("老年") || precaution.contains("老人"))) {
            return true;
        }
        
        return false;
    }
    
    private ReviewResult createReviewResult(Long prescriptionId, String reviewType, String severity,
                                          String message, String recommendation, String affectedDrugs,
                                          String conflictDetails) {
        ReviewResult result = new ReviewResult();
        result.setPrescriptionId(prescriptionId);
        result.setReviewType(reviewType);
        result.setSeverity(severity);
        result.setMessage(message);
        result.setRecommendation(recommendation);
        result.setAffectedDrugs(affectedDrugs);
        result.setConflictDetails(conflictDetails);
        result.setIsOverridden(false);
        result.setIsResolved(false);
        result.setCreatedAt(LocalDateTime.now());
        result.setCreatedBy("SYSTEM");
        
        return result;
    }
    
    private void updatePrescriptionReviewStatus(Prescription prescription, List<ReviewResult> reviewResults) {
        prescription.setIsReviewed(true);
        prescription.setReviewedAt(LocalDateTime.now());
        prescription.setReviewedBy("SYSTEM");
        
        boolean hasErrors = reviewResults.stream().anyMatch(r -> "ERROR".equals(r.getSeverity()));
        boolean hasWarnings = reviewResults.stream().anyMatch(r -> "WARNING".equals(r.getSeverity()));
        
        if (hasErrors) {
            prescription.setReviewStatus("FAILED");
            prescription.setReviewComments("发现严重问题，需要处理后才能执行");
        } else if (hasWarnings) {
            prescription.setReviewStatus("WARNING");
            prescription.setReviewComments("发现警告信息，建议医师确认");
        } else {
            prescription.setReviewStatus("PASSED");
            prescription.setReviewComments("审查通过");
        }
        
        prescriptionService.save(prescription);
    }
    
    /**
     * 检查特殊人群用药（慢病特殊人群）
     */
    private List<ReviewResult> checkSpecialPopulations(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        Patient patient = prescription.getPatient();
        
        if (patient == null || patient.getMedicalHistory() == null) {
            return results;
        }
        
        List<String> medicalHistory = Arrays.asList(patient.getMedicalHistory().split(","));
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        
        for (PrescriptionItem item : items) {
            Optional<DrugNode> drugNodeOpt = drugKnowledgeService.findDrugByCode(item.getDrugCode());
            if (!drugNodeOpt.isPresent()) continue;
            DrugNode drugNode = drugNodeOpt.get();
            
            // 肾功能不全患者
            if (hasCondition(medicalHistory, "肾功能不全", "慢性肾病", "CKD")) {
                if (isNSAID(drugNode) || needRenalAdjustment(drugNode)) {
                    results.add(createReviewResult(
                        prescription.getPrescriptionId(),
                        "SPECIAL_POPULATION",
                        "WARNING",
                        String.format("特殊人群警告：肾功能不全患者使用%s需谨慎", drugNode.getDrugName()),
                        "建议调整剂量或选择其他药物",
                        drugNode.getDrugName(),
                        "患者存在肾功能不全"
                    ));
                }
            }
            
            // 肝功能不全患者
            if (hasCondition(medicalHistory, "肝功能不全", "肝硬化", "慢性肝病")) {
                if (needHepaticAdjustment(drugNode)) {
                    results.add(createReviewResult(
                        prescription.getPrescriptionId(),
                        "SPECIAL_POPULATION",
                        "WARNING",
                        String.format("特殊人群警告：肝功能不全患者使用%s需谨慎", drugNode.getDrugName()),
                        "建议调整剂量或监测肝功能",
                        drugNode.getDrugName(),
                        "患者存在肝功能不全"
                    ));
                }
            }
            
            // 糖尿病患者
            if (hasCondition(medicalHistory, "糖尿病", "2型糖尿病", "1型糖尿病")) {
                if (isSteroid(drugNode)) {
                    results.add(createReviewResult(
                        prescription.getPrescriptionId(),
                        "SPECIAL_POPULATION",
                        "WARNING",
                        String.format("特殊人群警告：糖尿病患者使用%s可能升高血糖", drugNode.getDrugName()),
                        "需监测血糖并可能调整降糖药物",
                        drugNode.getDrugName(),
                        "患者存在糖尿病"
                    ));
                }
            }
        }
        
        return results;
    }
    
    /**
     * 检查性别相关用药限制
     */
    private List<ReviewResult> checkGenderRestrictions(Prescription prescription) {
        List<ReviewResult> results = new ArrayList<>();
        Patient patient = prescription.getPatient();
        
        if (patient == null || patient.getGender() == null) {
            return results;
        }
        
        List<PrescriptionItem> items = prescription.getPrescriptionItems();
        
        for (PrescriptionItem item : items) {
            Optional<DrugNode> drugNodeOpt = drugKnowledgeService.findDrugByCode(item.getDrugCode());
            if (!drugNodeOpt.isPresent()) continue;
            DrugNode drugNode = drugNodeOpt.get();
            
            // 孕妇禁忌
            if ("女".equals(patient.getGender()) && 
                patient.getIsPregnant() != null && patient.getIsPregnant()) {
                
                if (isPregnancyContraindicated(drugNode)) {
                    results.add(createReviewResult(
                        prescription.getPrescriptionId(),
                        "GENDER_RESTRICTION",
                        "ERROR",
                        String.format("性别禁忌：%s为妊娠禁忌药物", drugNode.getDrugName()),
                        "建议更换为妊娠期安全的药物",
                        drugNode.getDrugName(),
                        "该药物禁用于孕妇"
                    ));
                }
            }
            
            // 哺乳期妇女
            if ("女".equals(patient.getGender()) && 
                patient.getIsLactating() != null && patient.getIsLactating()) {
                
                if (isLactationContraindicated(drugNode)) {
                    results.add(createReviewResult(
                        prescription.getPrescriptionId(),
                        "GENDER_RESTRICTION", 
                        "WARNING",
                        String.format("性别限制：%s在哺乳期使用需谨慎", drugNode.getDrugName()),
                        "建议权衡利弊或暂停哺乳",
                        drugNode.getDrugName(),
                        "该药物可能通过乳汁分泌"
                    ));
                }
            }
        }
        
        return results;
    }
    
    /**
     * 去重审查结果
     */
    private List<ReviewResult> deduplicateResults(List<ReviewResult> results) {
        Map<String, ReviewResult> uniqueResults = new HashMap<>();
        
        for (ReviewResult result : results) {
            String key = result.getReviewType() + "_" + 
                        result.getDrugName() + "_" + 
                        (result.getInteractingDrug() != null ? result.getInteractingDrug() : "");
            
            if (!uniqueResults.containsKey(key)) {
                uniqueResults.put(key, result);
            } else {
                // 保留更严重的警告
                ReviewResult existing = uniqueResults.get(key);
                if (getSeverityLevel(result.getSeverity()) > getSeverityLevel(existing.getSeverity())) {
                    uniqueResults.put(key, result);
                }
            }
        }
        
        return new ArrayList<>(uniqueResults.values());
    }
    
    private int getSeverityLevel(String severity) {
        return switch (severity) {
            case "ERROR" -> 3;
            case "WARNING" -> 2;
            case "INFO" -> 1;
            default -> 0;
        };
    }
    
    private boolean hasCondition(List<String> medicalHistory, String... conditions) {
        String history = String.join(" ", medicalHistory).toLowerCase();
        return Arrays.stream(conditions)
            .anyMatch(condition -> history.contains(condition.toLowerCase()));
    }
    
    private boolean isNSAID(DrugNode drugNode) {
        if (drugNode.getCategory() != null && drugNode.getCategory().contains("非甾体抗炎药")) {
            return true;
        }
        String[] nsaids = {"布洛芬", "双氯芬酸", "吲哚美辛", "塞来昔布", "萘普生", "美洛昔康"};
        return Arrays.stream(nsaids)
            .anyMatch(nsaid -> drugNode.getCommonName() != null && 
                              drugNode.getCommonName().contains(nsaid));
    }
    
    private boolean isSteroid(DrugNode drugNode) {
        if (drugNode.getCategory() != null && drugNode.getCategory().contains("糖皮质激素")) {
            return true;
        }
        String[] steroids = {"泼尼松", "甲泼尼龙", "地塞米松", "氢化可的松", "倍他米松"};
        return Arrays.stream(steroids)
            .anyMatch(steroid -> drugNode.getCommonName() != null && 
                                drugNode.getCommonName().contains(steroid));
    }
    
    private boolean needRenalAdjustment(DrugNode drugNode) {
        if (drugNode.getPrecaution() == null) return false;
        return drugNode.getPrecaution().contains("肾") || 
               drugNode.getPrecaution().contains("肌酐清除率");
    }
    
    private boolean needHepaticAdjustment(DrugNode drugNode) {
        if (drugNode.getPrecaution() == null) return false;
        return drugNode.getPrecaution().contains("肝") || 
               drugNode.getPrecaution().contains("转氨酶");
    }
    
    private boolean isPregnancyContraindicated(DrugNode drugNode) {
        String[] contraindicatedDrugs = {
            "华法林", "甲氨蝶呤", "异维A酸", "沙利度胺", 
            "米索前列醇", "卡马西平", "苯妥英钠", "丙戊酸钠"
        };
        
        if (drugNode.getContraindication() != null && 
            drugNode.getContraindication().contains("妊娠")) {
            return true;
        }
        
        return Arrays.stream(contraindicatedDrugs)
            .anyMatch(cd -> drugNode.getCommonName() != null && 
                           drugNode.getCommonName().contains(cd));
    }
    
    private boolean isLactationContraindicated(DrugNode drugNode) {
        if (drugNode.getContraindication() != null && 
            drugNode.getContraindication().contains("哺乳")) {
            return true;
        }
        
        if (drugNode.getPrecaution() != null && 
            drugNode.getPrecaution().contains("乳汁")) {
            return true;
        }
        
        return false;
    }
}